package com.huwei.modules.base.util.cryption;

import java.io.UnsupportedEncodingException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

import javax.crypto.Cipher;

import lombok.Data;

/**
 * 	钥匙对加解密工具
 * @author huwei
 *
 */
public class KeyPairUtil {
	/**
	 * 编码
	 */
	private static final String UTF8 = "UTF-8";
	/**
	 * 加密算法RSA
	 */
	private static final String KEY_ALGORITHM = "RSA";
	/**
	 * 密钥长度
	 */
	private static final int KEY_MAX_LENGTH = 1024;
	
	/**
	 * <p>
	 * 生成密钥对(公钥和私钥)
	 * </p>
	 * @return
	 * @throws Exception
	 */
	public static Keys createKeys() throws Exception {
		KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
		keyPairGen.initialize(KEY_MAX_LENGTH);
		KeyPair keyPair = keyPairGen.generateKeyPair();
		RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
		RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
		return new Keys(privateKey ,publicKey);
	}
	
	/**
	 * 公钥加密
	 * 
	 * @param key 公钥
	 * @param data 明文
	 * @return <b>String</b> 密文<b><br/>null</b> 加密失败
	 */
	public static String encryptByPublicKey(String key, byte[] data) {
		try {
			RSAPublicKey publicKey = parsePublicKey(key);
			Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
			cipher.init(Cipher.ENCRYPT_MODE, publicKey);
			byte[] rsa = cipher.doFinal(data);
			return Base64.getEncoder().encodeToString(rsa);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 	公钥加密
	 * 
	 * @param key 公钥
	 * @param data 明文
	 * @return <b>String</b> 密文<b><br/>null</b> 加密失败
	 */
	public static String encryptByPublicKey(String key, String data) {
		try {
			return encryptByPublicKey(key, data.getBytes(UTF8));
		} catch (UnsupportedEncodingException e) {
			return encryptByPublicKey(key, data.getBytes());
		}
	}
	
	/**
	 * 私钥解密
	 * 
	 * @param key 私钥
	 * @param data 密文
	 * @return <b>String</b> 明文<b><br/>null</b> 解密失败
	 */
	public static String decryptByPrivateKey(String key, byte[] data) {
		try {
			RSAPrivateKey privateKey = parsePrivateKey(key);
			Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
			cipher.init(Cipher.DECRYPT_MODE, privateKey);
			byte[] rsa = cipher.doFinal(data);
			return new String(rsa, UTF8);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 私钥解密
	 * 
	 * @param key 私钥
	 * @param data 密文
	 * @return <b>String</b> 明文<b><br/>null</b> 解密失败
	 */
	public static String decryptByPrivateKey(String key, String data) {
		return decryptByPrivateKey(key, Base64.getDecoder().decode(data));
	}
	
	static private String encodeKey(Key key) {
		return Base64.getEncoder().encodeToString(key.getEncoded());
	}
	
	static private RSAPrivateKey parsePrivateKey(String key) {
		try {
			byte[] keyBytes = Base64.getDecoder().decode(key);
			PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
			KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM);
			return (RSAPrivateKey) factory.generatePrivate(spec);
		} catch (Exception e) {
		}
		return null;
	}
	
	static private RSAPublicKey parsePublicKey(String key) {
		try {
			byte[] keyBytes = Base64.getDecoder().decode(key);
			X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
			KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM);
			return (RSAPublicKey) factory.generatePublic(spec);
		} catch (Exception e) {
		}
		return null;
	}
	
	@Data
	static public class Keys {
		private String privateKey;
		private String publicKey;
		public Keys(RSAPrivateKey privateKey2, RSAPublicKey publicKey2) {
			this.privateKey = encodeKey(privateKey2);
			this.publicKey = encodeKey(publicKey2);
		}
	}
	
//	static public void main(String[] args) throws Exception {
//		Keys keys = createKeys();
//		System.out.println("private Key :" + keys.getPrivateKey());
//		System.out.println("public key :" + keys.getPublicKey());
//		String source = "hello keys util";
//		
//		String s = encryptByPublicKey(keys.getPublicKey(), source);
//		System.out.println(s);
//		
//		System.out.println("--- decrypt ---");
//		String ss = decryptByPrivateKey(keys.getPrivateKey(), s);
//		System.out.println(ss);
//	}
}
